/**
 *  Copyright Matt Silbernagel 2010
 *  
 *	This file is part of MobilePrinting.
 *
 *	MobilePrinting is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  MobilePrinting is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with MobilePrinting.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.uc.labs.MobilePrinting.PrintUtils;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

import edu.uc.labs.MobilePrinting.OSUtils.Writer;

import static edu.uc.labs.MobilePrinting.Configurator.*;

public class PrinterWriter extends Writer {

	public PrinterWriter() throws ParserConfigurationException {
		super();
	}
	
	public boolean writeBlank() {
		
		boolean created = true;
		
		Element root 	   = doc.createElement("CONFIGURATIONS");
		Element srvupdate  = doc.createElement("SRVUPDATE");
		Element cfgversion = doc.createElement("CFGVERSION");
		srvupdate.appendChild(cfgversion);
		
		Element computer = doc.createElement("COMPUTER");
		Element ip       = doc.createElement("IP");
		Element subnet   = doc.createElement("SUBNET");
		Element os       = doc.createElement("OS");
		computer.appendChild(ip);
		computer.appendChild(subnet);
		computer.appendChild(os);
		
		Element printers = doc.createElement("PRINTERS");
		
		root.appendChild(srvupdate);
		root.appendChild(computer);
		root.appendChild(printers);
		
		doc.appendChild(root);
		
		ByteArrayOutputStream xmlBaos = new ByteArrayOutputStream();

		DOMSource source = new DOMSource(doc);
		try {
			transformer.transform(source, new StreamResult(xmlBaos));
		} catch (TransformerException e1) {
			logger.error(e1.toString());
		}
		

		FileWriter fstream;
		try {
			fstream = new FileWriter( new File(USERSPACE + XMLFILE) );
			BufferedWriter bOut = new BufferedWriter(fstream);
			bOut.write(xmlBaos.toString());
			bOut.close();
			created = true;
		} catch (IOException e) {
			logger.error(e.toString());
		}
		
		return created;
	}


	
	/*
	 * The name of the file to write is the name of the printer zone There will
	 * be one cache file per printer zone so when the user enters a new zone
	 * that printer will be the default printer installed, which is also the
	 * last printer in that zone that the user installed
	 */
	public static void writeCache(Printer p, String file)
			throws ParserConfigurationException, IOException {
		TransformerFactory tFactory = null;
		Transformer transformer = null;
		try {
			tFactory = TransformerFactory.newInstance();
			transformer = tFactory.newTransformer();
		} catch (Exception e) {
			logger.debug(e.toString());
		}

		transformer.setOutputProperty("encoding", "UTF-8");

		DocumentBuilder builder;
		Document doc;
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		builder = factory.newDocumentBuilder();
		doc = builder.newDocument();

		doc.setXmlStandalone(true);

		Element root = doc.createElement("CONFIGURATIONS");
		Element e = doc.createElement("PRINTERS");
		
		Element e2 = doc.createElement("PRINTER");
		
		Text name = doc.createTextNode("" + p.getName());
		Element e3 = doc.createElement("NAME");
		e3.appendChild(name);

		Text server = doc.createTextNode("" + p.getServer());
		Element e4 = doc.createElement("SERVER");
		e4.appendChild(server);

		Text queue = doc.createTextNode("" + p.getQueue());
		Element e5 = doc.createElement("QUEUE");
		e5.appendChild(queue);

		/*
		 * This printer object has the absolute path
		 * to the ppd already. But when we parse the 
		 * xml file we are expecting just a file name.
		 * The current remedy is to just grab the ppdFileName
		 */
		Text driver = doc.createTextNode("" + p.getPPDFileName());
		Element e6 = doc.createElement("DRIVER");
		e6.appendChild(driver);

		Text zone = doc.createTextNode("" + p.getZone());
		Element e7 = doc.createElement("ZONE");
		e7.appendChild(zone);

		Text location = doc.createTextNode("" + p.getLocation());
		Element e8 = doc.createElement("LOCATION");
		e8.appendChild(location);

		e2.appendChild(e3);
		e2.appendChild(e4);
		e2.appendChild(e5);
		e2.appendChild(e6);
		e2.appendChild(e7);
		e2.appendChild(e8);

		e.appendChild(e2);
		root.appendChild(e);
		doc.appendChild(root);

		ByteArrayOutputStream xmlBaos = new ByteArrayOutputStream();

		DOMSource source = new DOMSource(doc);
		try {
			transformer.transform(source, new StreamResult(xmlBaos));
		} catch (TransformerException e1) {
			e1.printStackTrace();
		}

		File f = new File(file);
		FileWriter fstream = new FileWriter(f);
		BufferedWriter bOut = new BufferedWriter(fstream);
		bOut.write(xmlBaos.toString());
		bOut.close();
	}

	/**
	 * Read the cache file.
	 * 
	 * @param zone
	 *            - The zone that the computer is currently in
	 * @return the printer object that represents the last printer installed in
	 *         this zone
	 */
	public static Printer getCache(String zone) {
		ArrayList<Printer> printer = null;
		try {
			String dir = CACHE + DELIM + zone + ".xml";
			PrinterParser parser = new PrinterParser();
			printer = parser.parse(dir);
			LOGGER.debug("trying to parse the file " + dir);
		} catch (SAXException ex) {
			logger.debug(ex.toString());
			return new Printer();
		} catch (IOException ex) {
			// return new Printer();
			logger.debug(ex.toString());
		} catch (XPathExpressionException ex) {
			// return new Printer();
			logger.debug(ex.toString());
		} catch (ParserConfigurationException ex) {
			// return new Printer();
			logger.debug(ex.toString());
		} catch (IndexOutOfBoundsException ex) {
			logger.debug(ex.toString());
		}

		if (printer.isEmpty()) {
			logger.debug("The Printer array list is empty...");
			return new Printer();
		}
		LOGGER.debug("PrintWriter#getCache: The printer I'm returning is: " + printer.get(0).toString());
		return printer.get(0);
	}

	/**
	 * Returns a printer object built from the 
	 * current.xml file
	 * @return
	 */
	public static Printer getCurrent() {
		ArrayList<Printer> printer = null;
		try {
			PrinterParser parser = new PrinterParser();
			printer = parser.parse(USERSPACE + CURRENT_PRINTER);
			LOGGER.debug("Trying to parse the file " + USERSPACE + CURRENT_PRINTER);
		} catch (SAXException e){
			LOGGER.error("SAXException while trying to parse " + USERSPACE + CURRENT_PRINTER + ": " + e.toString());
			return new Printer();
		} catch (XPathExpressionException e) {
			LOGGER.error("XPathExpressionException while trying to parse " + USERSPACE + CURRENT_PRINTER + ": " + e.toString());		
			return new Printer();
		} catch (IOException e) {
			LOGGER.error("IOException while trying to parse " + USERSPACE + CURRENT_PRINTER + ": " + e.toString());
			return new Printer();
		} catch (ParserConfigurationException e) {
			LOGGER.error("ParserConfigurationException while trying to parse " + USERSPACE + CURRENT_PRINTER + ": " + e.toString());
			return new Printer();
		}
		
		if(printer.isEmpty()){
			logger.debug("The Printer array list is empty");
			return new Printer();
		}
		return printer.get(0); 
	}
}
